# -*- coding: utf-8 -*-

import socket, wx, thread
from packets import *
from packetevents import *

ID_DISCONNECTED = 0
ID_CONNECTED = 1
ID_LISTENING = 2
ID_CONNECTING = 3

def Loop(nw, *args):
    num = 0
    if nw.GetState() == ID_CONNECTING:
        nw.OnConnect()
    else:
        nw.OnListen()
    while nw.GetState() == ID_CONNECTED:
        #if len(nw.GetBuffer()) > 0:
            #nw.Flush()
        buffer = nw.Recv()
        if buffer != '':
            buffer.decode('utf-8')
            index = 0
            split = buffer.split('/f/')
            while split[index] != '':
                id = int(split[index])
                index += 1
                fields = int(split[index])
                index += 1
                data = split[index:index+fields]
                index += fields
                reader = PacketReader(id, fields, data)
                nw.OnPacket(reader)

                
class Network():
    def __init__(self, frame):
        self._frame = frame
        self._connection = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self._state = ID_DISCONNECTED
        self._buffer = ''
        self._host = ('', 0)
        self._handlers = dict()
        self._nick = ''
        self._thread = ''
        self.PacketHandlers()

    def SetState(self, state):
        self._state = state

    def GetState(self):
        return self._state

    def GetHost(self):
        return self._host

    def GetFrame(self):
        return self._frame

    def Connect(self, address, port, nick):
        self._nick = nick
        self._host = (address,port)
        self.SetState(ID_CONNECTING)
        self._thread = thread.start_new_thread(Loop, (self,))

    def Listen(self, port, nick):
        self._nick = nick
        self._host = ('', port)
        self.SetState(ID_LISTENING)
        self._thread = thread.start_new_thread(Loop, (self,))

    def OnConnect(self):
        self._connection.connect(self.GetHost())
        self._frame._nick = self._nick
        self.SetState(ID_CONNECTED)
        self.Write(ConnectPacket(self._nick).Build())

    def OnListen(self):
        listener = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        listener.bind(self.GetHost())
        listener.listen(1)
        conn, address = listener.accept()
        self._connection = conn
        self._frame._nick = self._nick
        self.SetState(ID_CONNECTED)
        self.Write(ConnectPacket(self._nick).Build())

    def Write(self, data, flush=True):
        self._buffer += data
        if flush:
            self.Flush()

    def Recv(self):
        return self._connection.recv(4096)

    def Flush(self):
        self._connection.send(self._buffer)
        self.ClearBuffer()
    
    def ClearBuffer(self):
        self._buffer = ''
        
    def GetBuffer(self):
        return self._buffer
    
    def Close(self):
        self._connection.close()
        self.SetState(ID_DISCONNECTED)
        
    def PacketHandlers(self):
        self._handlers[PACKET_CONNECT] = PacketConnectEvent
        self._frame.Connect(-1, -1, EVT_CONNECT, self._frame.OnConnectPacket)
        self._handlers[PACKET_CHAT] = PacketChatEvent
        self._frame.Connect(-1, -1, EVT_CHAT, self._frame.OnChatPacket)
        self._handlers[PACKET_DECK] = PacketDeckEvent
        self._frame.Connect(-1, -1, EVT_DECK, self._frame.OnDeckPacket)
        self._handlers[PACKET_DRAW] = PacketDrawEvent
        self._frame.Connect(-1, -1, EVT_DRAW, self._frame.OnDrawPacket)
        self._handlers[PACKET_SHUFFLE] = PacketShuffleEvent
        self._frame.Connect(-1, -1, EVT_SHUFFLE, self._frame.OnShufflePacket)
        self._handlers[PACKET_CARDMOVE] = PacketCardMoveEvent
        self._frame.Connect(-1, -1, EVT_CARDMOVE, self._frame.OnCardMovePacket)
        self._handlers[PACKET_CARDFLIP] = PacketCardFlipEvent
        self._frame.Connect(-1, -1, EVT_CARDFLIP, self._frame.OnCardFlipPacket)
        self._handlers[PACKET_LIFECHANGE] = PacketLifeChangeEvent
        self._frame.Connect(-1, -1, EVT_LIFECHANGE, self._frame.OnLifeChangePacket)
        self._handlers[PACKET_PHASE] = PacketPhaseEvent
        self._frame.Connect(-1, -1, EVT_PHASE, self._frame.OnPhasePacket)
        self._handlers[PACKET_ROLL] = PacketRollEvent
        self._frame.Connect(-1, -1, EVT_ROLL, self._frame.OnRollPacket)

    def GetHandler(self, id):
        return self._handlers[id]

    def OnPacket(self, reader):
        handler = self.GetHandler(reader.GetId())
        wx.PostEvent(self._frame, handler(reader))
    
    def IsConnected(self):
        if self._state == ID_CONNECTED:
            return 1
        return 0

class PacketReader():
    def __init__(self, id, fields, data):
        self._id = id
        self._fields = fields
        self._data = data
        self._index = -1
    
    def ReadBool(self):
        if self._index >= self._fields-1:
            return False
        self._index += 1
        return bool(int(self._data[self._index]))
    
    def ReadInt(self):
        if self._index >= self._fields-1:
            return int(-1)
        self._index += 1
        return int(self._data[self._index])
    
    def ReadFloat(self):
        if self._index >= self._fields-1:
            return float(-1)
        self._index += 1
        return float(self._data[self._index])
    
    def ReadLong(self):
        if self._index >= self._fields-1:
            return long(-1)
        self._index += 1
        return long(self._data[self._index])
    
    def ReadString(self):
        if self._index >= self._fields-1:
            return str('')
        self._index += 1
        return str(self._data[self._index])

    def GetId(self):
        return self._id

    def GetFields(self):
        return self._fields
    
    def PeekInt(self, idx=-1):
        if idx == -1:
            idx = self._index+1
        if self._index >= self._fields-1:
            return int(-1)
        return int(self._data[idx])
    
    def PeekFloat(self, idx=-1):
        if idx == -1:
            idx = self._index+1
        if self._index >= self._fields-1:
            return float(-1)
        return float(self._data[idx])
    
    def PeekLong(self, idx=-1):
        if idx == -1:
            idx = self._index+1
        if self._index >= self._fields-1:
            return long(-1)
        return long(self._data[idx])
    
    def PeekString(self, idx=-1):
        if idx == -1:
            idx = self._index+1
        if self._index >= self._fields-1:
            return str('')
        return str(self._data[idx])